package com.alibaba.citrus.cr.sales.plan.facade.service.statistics;

import com.alibaba.citrus.cr.common.annotation.FacadeInvoker;
import com.alibaba.citrus.cr.common.exception.FacadeException;
import com.alibaba.citrus.cr.common.lock.RedisLock;
import com.alibaba.citrus.cr.common.log.CommonErrorCode;
import com.alibaba.citrus.cr.sales.plan.contants.SalesPlanLockKey;
import com.alibaba.citrus.cr.sales.plan.facade.service.statistics.stat.ConformityStatService;
import com.alibaba.citrus.cr.sales.plan.facade.service.statistics.stat.customer.CustomerStatService;
import com.alibaba.citrus.cr.sales.plan.facade.service.statistics.stat.model.SalesPlanStatRequest;
import com.alibaba.citrus.cr.sales.plan.model.enums.SalesPlanStatusEnum;
import com.alibaba.citrus.cr.sales.plan.repository.SalesPlanCustomerStatRepository;
import com.alibaba.citrus.cr.sales.plan.repository.SalesPlanRepository;
import com.alibaba.citrus.cr.sales.plan.repository.SalesPlanScItemStatRepository;
import com.alibaba.citrus.cr.sales.plan.sdo.SalesPlanSDO;
import com.alibaba.citrus.cr.sales.plan.api.statistics.SalesPlanStatService;
import com.alibaba.citrus.cr.sales.plan.dto.api.request.QuerySalesPlanRequest;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.lattice2.epoch.middleware.mq.runtime.EpochMessageService;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.bcorder.contants.BcOrderConstants;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.util.Calendar;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * @author luyi
 * @date 2021/9/25 10:12 下午
 */
@Service
public class SalesPlanStatServiceImpl implements SalesPlanStatService {

    private static final Log log = Log.getLogger(SalesPlanStatServiceImpl.class);

    @Resource
    private SalesPlanRepository salesPlanRepository;
    @Resource
    private SalesPlanCustomerStatRepository salesPlanCustomerStatRepository;
    @Resource
    private SalesPlanScItemStatRepository salesPlanScItemStatRepository;

    @Resource(name = "salesPlanTaskExecutor")
    private ThreadPoolTaskExecutor salesPlanTaskExecutor;

    @Resource
    private EpochMessageService epochMessageService;

    /**
     * 计划明细汇总
     * 计划状态 待锁定 待回复    客户任务量发布
     * 触发汇总
     *
     * @param planId 计划id
     * @return
     */
    @FacadeInvoker
    @Override
    public Result<Boolean> planCollect(String planId) {
        //是否更新extend表
        Boolean isUpdateExtend = false;
        if("#".equals(planId.substring(0,1))){
            isUpdateExtend = true;
            planId = planId.substring(1);
        };

        QuerySalesPlanRequest request = new QuerySalesPlanRequest();
        request.setId(planId);
        SalesPlanSDO salesPlanSDO = salesPlanRepository.load(request);
        if (salesPlanSDO == null) {
            throw new FacadeException("OTS-02-002-00-16-001");
        }
        if (SalesPlanStatusEnum.CANCEL.getCode().equals(salesPlanSDO.getStatus())) {
            //计划已经取消
            throw new FacadeException("OTS-02-002-00-16-003");
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date(Long.parseLong(salesPlanSDO.getPlanTime())));
        String year = Objects.toString(calendar.get(Calendar.YEAR), null);
        String month = Objects.toString(calendar.get(Calendar.MONTH) + 1, null);

        try (RedisLock lock = new RedisLock(BcOrderConstants.REDIS_CACHE_CODE(), SalesPlanLockKey.getPlanStatLockKey(planId))) {
            boolean locked = lock.lock();
            if (!locked) {
                log.error("SalesPlanStatServiceImpl#planCollect.getLock.fail planId=" + planId);
                return Result.fail("OTS-02-006-00-16-005", "该计划正在汇总，请稍后重试");
            }
            log.info("SalesPlanStatServiceImpl#planCollect_start_planId=" + planId);
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            deleteStatData(planId);

            SalesPlanStatRequest statRequest = new SalesPlanStatRequest(salesPlanSDO, year, month, isUpdateExtend);
            final CountDownLatch latch = new CountDownLatch(2);
            salesPlanTaskExecutor.execute(new CustomerStatService(statRequest, latch));
            salesPlanTaskExecutor.execute(new ConformityStatService(statRequest, latch));
            latch.await(35,TimeUnit.SECONDS);
            stopWatch.stop();

            log.info("SalesPlanStatServiceImpl#planCollect_end_planId=" + planId + ",elapsed time:" + stopWatch.getTotalTimeMillis() + "ms");

        } catch (Exception e) {
            log.error("SalesPlanStatServiceImpl#planCollect_fail  ", e);
            return Result.fail(CommonErrorCode.SYSTEM_ERROR, "系统开小差了");
        }

        //发消息，sales-plan消费，计划汇总分仓货品维度
        epochMessageService.sendMessage("bc_sales_plan_collect_message", "BC_SALES_PLAN", "sales_plan_collect_warehouse", planId);
        log.info("salesplan_center_message_send_mq,mqCode=bc_sales_plan_collect_message,topic=BC_SALES_PLAN,tag=sales_plan_collect_warehouse,body={}"+planId);

        return Result.success(true);
    }

    @FacadeInvoker
    @Override
    public Result<Boolean> deleteStatData(String planId) {
        Boolean deletePlanCustomer = salesPlanCustomerStatRepository.deletePlanCustomerByPlanId(planId);
        Boolean deletePlanScItem = salesPlanScItemStatRepository.deletePlanScItemByPlanId(planId);
        return Result.success(deletePlanCustomer && deletePlanScItem);
    }

    @Override
    public Result<Boolean> consumePlanCollect(String message) {
        if (StringUtils.isBlank(message)) {
            return Result.success(true);
        }
        Result<Boolean> booleanResult = null;
        try {
            booleanResult = planCollect(message);
        } catch (Exception e) {
            log.error("SalesPlanStatServiceImpl#consumePlanCollect_fail " + "触发月度计划汇总消费异常", e);
        }
        return booleanResult == null ? Result.success(true) : booleanResult;
    }

}
